﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using ArgusLib.Fractals;

namespace Fraktalysator.Forms
{
	partial class RendererParameterForm : ToolForm
	{
		#region Private Fields
		IDataSetProvider[] dataSetProviders;
		IDataSetProvider[] listedDataSetProviders;
		IRendererProvider[] rendererProviders;
		IRendererProvider[] listedRendererProviders;
		#endregion

		#region Properties
		private IRenderParameterInputControl inputControl;
		public IRenderParameterInputControl InputControl
		{
			get { return this.inputControl; }
			set
			{
				if (this.inputControl != null)
					this.inputControl.RedrawRequested -= InputControl_RedrawRequested;
				this.inputControl = value;
				this.inputControl.RedrawRequested += InputControl_RedrawRequested;
				this.pParameterInputControl.Controls.Clear();
				this.pParameterInputControl.Controls.Add(value.Control);
			}
		}

		public IDataSetProvider DataSetProvider
		{
			get
			{
				if (this.cbRenderer.SelectedIndex < 0)
					return null;
				return this.listedDataSetProviders[this.cbRenderer.SelectedIndex];
			}
		}
		#endregion

		#region Constructors
		public RendererParameterForm()
		{
			InitializeComponent();

			Assembly assembly = Assembly.GetAssembly(typeof(IDataSetProvider));
			this.dataSetProviders = assembly.GetInterfaceImplementations<IDataSetProvider>();
			assembly = Assembly.GetAssembly(typeof(IRendererProvider));
			this.rendererProviders = assembly.GetInterfaceImplementations<IRendererProvider>();
		}
		#endregion

		#region Public Methods
		public void InitializeRendererList(IFractal fractal)
		{
			this.cbRenderer.Items.Clear();
			if (fractal == null)
				return;

			IRendererProvider oldProvider = null;
			if (this.cbRenderer.SelectedIndex > -1)
			{
				oldProvider = this.listedRendererProviders[this.cbRenderer.SelectedIndex];
			}
			List<IRendererProvider> rProviders = new List<IRendererProvider>();
			List<IDataSetProvider> dProviders = new List<IDataSetProvider>();
			foreach (IRendererProvider rProvider in this.rendererProviders)
			{
				IRenderer renderer = rProvider.GetRenderer();
				if (renderer.SupportsDataSet(fractal.DataSet) == true)
				{
					rProviders.Add(rProvider);
					dProviders.Add(fractal.DataSetProvider);
				}
				else
				{
					IDataSetProvider dataSetProvider = renderer.GetCompatibleDataSetProvider();
					if (fractal.SupportsDataSetProvider(dataSetProvider) == true)
					{
						rProviders.Add(rProvider);
						dProviders.Add(dataSetProvider);
						continue;
					}
				}

				foreach (IDataSetProvider dataSetProvider in this.dataSetProviders)
				{
					if (fractal.SupportsDataSetProvider(dataSetProvider) == false)
						continue;
					if (renderer.SupportsDataSet(dataSetProvider.DataSetType) == false)
						continue;

					rProviders.Add(rProvider);
					dProviders.Add(dataSetProvider);
				}
			}
			this.listedRendererProviders = rProviders.ToArray();
			this.listedDataSetProviders = dProviders.ToArray();

			for (int i = 0; i < this.listedRendererProviders.Length; i++)
			{
				this.cbRenderer.Items.Add(this.listedRendererProviders[i].RendererName);
				if (this.listedRendererProviders[i] == oldProvider)
					this.cbRenderer.SelectedIndex = i;
				else if (this.listedRendererProviders[i] is Fraktalysator.RendererProviders.EsacpeTimeSmootherProvider)
					this.cbRenderer.SelectedIndex = i;
			}
		}

		public IRenderer GetRenderer()
		{
			IRenderer renderer = this.listedRendererProviders[this.cbRenderer.SelectedIndex].GetRenderer();
			renderer.Parameter = this.InputControl.Parameter;
			return renderer;
		}

		public void SelectRenderer(IRenderer renderer)
		{
			Type rType = renderer.GetType();
			for (int i = 0; i < this.listedRendererProviders.Length; i++)
			{
				if (this.listedRendererProviders[i].RendererType == rType)
				{
					this.cbRenderer.SelectedIndex = i;
					break;
				}
			}
			this.InputControl.Parameter = renderer.Parameter;
		}
		#endregion

		#region Non-Public Methods
		private void cbRenderer_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (this.cbRenderer.SelectedIndex < 0)
				return;

			IRendererProvider rProvider = this.listedRendererProviders[this.cbRenderer.SelectedIndex];
			IRenderParameterInputControl inputControl = rProvider.GetParameterInputControl();
			if (this.InputControl == null || this.InputControl.GetType() != inputControl.GetType())
			{
				this.InputControl = rProvider.GetParameterInputControl();
				this.inputControl.Control.Dock = DockStyle.Fill;
				this.InputControl.Parameter = rProvider.GetStandardParameter();
				this.InputControl_RedrawRequested(null, EventArgs.Empty);
			}
		}
		#endregion

		#region Eventhandling
		public event EventHandler RedrawRequested;

		void InputControl_RedrawRequested(object sender, EventArgs e)
		{
			if (this.cbRedraw.Checked == false)
				return;
			if (this.RedrawRequested != null)
				this.RedrawRequested(sender, e);
		}
		#endregion
	}
}
